import re


def to_hump(name: str, first=True):
    seps = column_split(name)
    ans = ''
    if first:
        ans += seps[0][0:1].upper() + seps[0][1:]
    else:
        ans += seps[0]
    if len(seps) > 1:
        ans += ''.join([sep[0:1].upper() + sep[1:] for sep in seps[1:]])
    return ans


def to_char_sep_lower(name: str, sep='_'):
    return sep.join(column_split(name))


def parse_json_metadata(base_class_name: str, data: dict):
    if isinstance(data, (tuple, list)):
        return parse_json_metadata(base_class_name, data[0])

    ans = []

    def _parse_json(d, name):
        info = {'class': name, 'fields': []}
        for k, v in d.items():
            if v is None:
                info['fields'].append({
                    'field': k,
                    'type': object,
                    'generics': []
                })
                continue
            tp = type(v)
            generic = []
            info['fields'].append({
                'field': k,
                'type': tp,
                'generics': generic
            })
            if tp == dict:
                _parse_json(v, k)
            elif tp in (tuple, list) and v[0]:
                tmp_tp, tmp_v = type(v[0]), v[0]
                while tmp_tp in (tuple, list):
                    generic.append(list)
                    if tmp_tp:
                        tmp_v = tmp_v[0]
                        tmp_tp = type(tmp_v)
                    else:
                        tmp_tp = object
                        break
                generic.append(tmp_tp)
                if tmp_tp == dict:
                    _parse_json(tmp_v, k)
        ans.append(info)

    _parse_json(data, base_class_name)
    return ans


def column_split(name: str, sep='_'):
    return re.sub("([a-z])([A-Z])", f"\\1{sep}\\2", name).lower().split(sep)


if __name__ == '__main__':
    meta = parse_json_metadata('JavaRootBean', {
        "name": "dragons",
        "age": 18,
        "addressPx": [{
              "id": 1,
              "address": "place"
        }],
        "labels": [1, 2]
    })
    for one in meta:
        print(one)
